﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once

#include "GcmpIfcInterface.h"
#include <map>
#include "UnitConverter.h"
#include "TransferOwnership.h"
#include "IIfcValueObject.h"
#include "IIfcEntity.h"
#include "IUnitDimension.h"
#include "WeakReferenceable.h"

namespace gcmp
{
    class IParameter;
    class IIfcEntity;
    struct UnitDimensionNames;

    /// \brief 参数自定义导出上下文，转换时可能用到的参数名，单位对象，单位量纲等。
    ///
    ///ConvertedUnitRatio一般传入值为1.0，表示原单位和转换后的系数保持1:1的关系，只在处理单位类型不能转换的情况下，才需要设置为其他值。
    ///例如：焦每千克（J/kg）1m2/s2转换为千焦每千克（KJ/Kg）1000m2/s2， 转换后的单位中有1000这个系数，这个系数并不能从单位类型中转换得到，
    ///此情况下convertedUnitRatio应该设置为1000.0, 反之如果从千焦每千克（KJ/Kg）1000m2/s2转换为焦每千克（J/kg）1m2/s2，则convertedUnitRatio应该设置为0.001.
    struct  IfcParameterCustomizedConvertContext
    {
        IfcParameterCustomizedConvertContext() {};
        
        IfcParameterCustomizedConvertContext(const IfcParameterCustomizedConvertContext& other) 
        {
            ParamName = other.ParamName;
            if (other.ParamValueObject != nullptr)
                ParamValueObject = TransferOwnership(other.ParamValueObject->Clone());
            if (other.ParamUnitObject != nullptr)
#pragma warning(push)
#pragma warning(disable: 4996)
                ParamUnitObject = TransferOwnership(other.ParamUnitObject->Clone());
#pragma warning(pop)
            if (other.UnitDimension != nullptr)
                UnitDimension = TransferOwnership(other.UnitDimension->Clone());
            OriginUnitNames = other.OriginUnitNames;
            ConvertedUnitNames = other.ConvertedUnitNames;
            ConvertedUnitRatio = other.ConvertedUnitRatio;
        };

        std::string                 ParamName;                       //参数名字
        OwnerPtr<IIfcValueObject>   ParamValueObject = nullptr;      //导出的参数值对象，由调用者创建后传入，该对象不允许传入空指针
        OwnerPtr<IIfcEntity>        ParamUnitObject = nullptr;       //导出单位对象，由调用者创建后传入，可以传入空指针
        OwnerPtr<IUnitDimension>    UnitDimension = nullptr;         //单位量纲，为空指针时导出的参数值不会被转换
        UnitDimensionNames          OriginUnitNames;                 //转换前的单位名集合
        UnitDimensionNames          ConvertedUnitNames;              //转换后的单位名集合
        double                      ConvertedUnitRatio = 1.0;        //转换后的单位的系数, 默认传入1.0
    };

    /// \brief IFC参数转换器，提供参数转换相关接口
    class IIfcParameterConverter:public WeakReferenceable
    {
    public:
        virtual ~IIfcParameterConverter() {}

    public:

        /// \brief 导出关联IFC对象的参数到buildingModel中
        ///
        /// \param relatedIfcEntities 导出参数时关联的IFC实体对象
        /// \param groupName 参数所在的组名
        /// \param parameters 平台参数集合
        /// \param nameOverrides 参数的重新命名集合
        /// \return 返回导出状态，true为导出参数成功，false为导出参数失败
        virtual bool ConvertParameters(const std::vector<const IIfcEntity*>& relatedIfcEntities,
            const std::wstring& groupName,
            const std::vector<OwnerPtr<IParameter>>& parameters,
            const std::vector<std::string>& nameOverrides) = 0;

        /// \brief 导出关联IFC对象的参数到buildingModel中
        ///
        /// \param relatedIfcEntities 导出参数时关联的IFC实体对象
        /// \param groupName 参数所在的组名
        /// \param paramConvertContextVec 自定义导出参数上下文结构的集合
        /// \return 返回导出状态，true为导出参数成功，false为导出参数失败
        /// 调用该方法一次，会生成一条ifcreldefinesbyproperties和一条ifcpropertyset数据，以及多条IfcPropertySingleValue的数据，
        /// paramConvertContextVec参数中的一条记录，在导出IFC时就对应一条IfcPropertySingleValue数据。
        virtual bool ConvertParameters(
            const std::vector<const IIfcEntity*>& relatedIfcEntities,
            const std::wstring& groupName,
            const std::vector<IfcParameterCustomizedConvertContext>& paramConvertContextVec) = 0;

    };
}
